home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / tack / control.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  13.8 KB  |  658 lines

  1. /*
  2. ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
  3. ** 
  4. ** This file is part of TACK.
  5. ** 
  6. ** TACK is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2, or (at your option)
  9. ** any later version.
  10. ** 
  11. ** TACK is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** 
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with TACK; see the file COPYING.  If not, write to
  18. ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. ** Boston, MA 02111-1307, USA.
  20. */
  21.  
  22. #include <tack.h>
  23.  
  24. #if HAVE_SYS_TIME_H
  25. #include <sys/time.h>
  26. #endif
  27.  
  28. MODULE_ID("$Id: control.c,v 1.3 2000/03/04 21:10:59 tom Exp $")
  29.  
  30. /* terminfo test program control subroutines */
  31.  
  32. #if HAVE_GETTIMEOFDAY
  33. #define MY_TIMER struct timeval
  34. #else
  35. #define MY_TIMER time_t
  36. #endif
  37.  
  38. /* globals */
  39. int test_complete;        /* counts number of tests completed */
  40.  
  41. char txt_longer_test_time[80];    /* +) use longer time */
  42. char txt_shorter_test_time[80];    /* -) use shorter time */
  43. int pad_test_duration = 1;    /* number of seconds for a pad test */
  44. int auto_pad_mode;        /* run the time tests */
  45. int no_alarm_event;        /* TRUE if the alarm has not gone off yet */
  46. int usec_run_time;        /* length of last test in microseconds */
  47. MY_TIMER stop_watch[MAX_TIMERS]; /* Hold the start timers */
  48.  
  49. char txt_longer_augment[80];    /* >) use bigger augment */
  50. char txt_shorter_augment[80];    /* <) use smaller augment */
  51.  
  52. /* caps under test data base */
  53. int tt_delay_max;        /* max number of milliseconds we can delay */
  54. int tt_delay_used;        /* number of milliseconds consumed in delay */
  55. const char *tt_cap[TT_MAX];    /* value of string */
  56. int tt_affected[TT_MAX];    /* lines or columns effected (repetition factor) */
  57. int tt_count[TT_MAX];        /* Number of times sent */
  58. int tt_delay[TT_MAX];        /* Number of milliseconds delay */
  59. int ttp;            /* number of entries used */
  60.  
  61. /* Saved value of the above data base */
  62. const char *tx_cap[TT_MAX];    /* value of string */
  63. int tx_affected[TT_MAX];    /* lines or columns effected (repetition factor) */
  64. int tx_count[TT_MAX];        /* Number of times sent */
  65. int tx_index[TT_MAX];        /* String index */
  66. int tx_delay[TT_MAX];        /* Number of milliseconds delay */
  67. int txp;            /* number of entries used */
  68. int tx_characters;        /* printing characters sent by test */
  69. int tx_cps;            /* characters per second */
  70. struct test_list *tx_source;    /* The test that generated this data */
  71.  
  72. extern struct test_menu pad_menu;    /* Pad menu structure */
  73. extern struct test_list pad_test_list[];
  74.  
  75. #define RESULT_BLOCK        1024
  76. static int blocks;        /* number of result blocks available */
  77. static struct test_results *results;    /* pointer to next available */
  78. struct test_results *pads[STRCOUNT];    /* save pad results here */
  79.  
  80. /*
  81. **    event_start(number)
  82. **
  83. **    Begin the stopwatch at the current time-of-day.
  84. */
  85. void
  86. event_start(int n)
  87. {
  88. #if HAVE_GETTIMEOFDAY
  89.     (void) gettimeofday(&stop_watch[n], (struct timezone *)0);
  90. #else
  91.     stop_watch[n] = time((time_t *)0);
  92. #endif
  93. }
  94.  
  95. /*
  96. **    event_time(number)
  97. **
  98. **    Return the number of milliseconds since this stop watch began.
  99. */
  100. long
  101. event_time(int n)
  102. {
  103. #if HAVE_GETTIMEOFDAY
  104.     MY_TIMER current_time;
  105.  
  106.     (void) gettimeofday(¤t_time, (struct timezone *)0);
  107.     return ((current_time.tv_sec - stop_watch[n].tv_sec) * 1000000)
  108.         + current_time.tv_usec - stop_watch[n].tv_usec;
  109. #else
  110.     return (time((time_t *)0) - stop_watch[n]) * 1000;
  111. #endif
  112. }
  113.  
  114. /*****************************************************************************
  115.  *
  116.  * Execution control for string capability tests
  117.  *
  118.  *****************************************************************************/
  119.  
  120. /*
  121. **    get_next_block()
  122. **
  123. **    Get a results block for pad test data.
  124. */
  125. static struct test_results *
  126. get_next_block(void)
  127. {
  128.     if (blocks <= 0) {
  129.         results = (struct test_results *)
  130.             malloc(sizeof(struct test_results) * RESULT_BLOCK);
  131.         if (!results) {
  132.             ptextln("Malloc failed");
  133.             return (struct test_results *) 0;
  134.         }
  135.         blocks = RESULT_BLOCK;
  136.     }
  137.     blocks--;
  138.     return results++;
  139. }
  140.  
  141. /*
  142. **    set_augment_txt()
  143. **
  144. **    Initialize the augment menu selections
  145. */
  146. void
  147. set_augment_txt(void)
  148. {
  149.     sprintf(txt_longer_augment,
  150.         ">) Change lines/characters effected to %d", augment << 1);
  151.     sprintf(txt_shorter_augment,
  152.         "<) Change lines/characters effected to %d", augment >> 1);
  153. }
  154.  
  155. void
  156. control_init(void)
  157. {
  158.     sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
  159.         pad_test_duration + 1);
  160.     sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
  161.         pad_test_duration - 1);
  162.     set_augment_txt();
  163. }
  164.  
  165. /*
  166. **    msec_cost(cap, affected-count)
  167. **
  168. **    Return the number of milliseconds delay needed by the cap.
  169. */
  170. int
  171. msec_cost(
  172.     const char *const cap,
  173.     int affcnt)
  174. {
  175.     int dec, value, total, star, ch;
  176.     const char *cp;
  177.  
  178.     if (!cap) {
  179.         return 0;
  180.     }
  181.     total = 0;
  182.     for (cp = cap; *cp; cp++) {
  183.         if (*cp == '$' && cp[1] == '<') {
  184.             star = 1;
  185.             value = dec = 0;
  186.             for (cp += 2; (ch = *cp); cp++) {
  187.                 if (ch >= '0' && ch <= '9') {
  188.                     value = value * 10 + (ch - '0');
  189.                     dec *= 10;
  190.                 } else
  191.                 if (ch == '.') {
  192.                     dec = 1;
  193.                 } else
  194.                 if (ch == '*') {
  195.                     star = affcnt;
  196.                 } else
  197.                 if (ch == '>') {
  198.                     break;
  199.                 }
  200.             }
  201.             if (dec > 1) {
  202.                 total += (value * star) / dec;
  203.             } else {
  204.                 total += (value * star);
  205.             }
  206.         }
  207.     }
  208.     return total;
  209. }
  210.  
  211. /*
  212. **    liberated(cap)
  213. **
  214. **    Return the cap without padding
  215. */
  216. char *
  217. liberated(char *cap)
  218. {
  219.     static char cb[1024];
  220.     char *ts, *ls;
  221.  
  222.     cb[0] = '\0';
  223.     ls = NULL;
  224.     if (cap) {
  225.         for (ts = cb; (*ts = *cap); ++cap) {
  226.             if (*cap == '$' && cap[1] == '<') {
  227.                 ls = ts;
  228.             }
  229.             ++ts;
  230.             if (*cap == '>') {
  231.                 if (ls) {
  232.                     ts = ls;
  233.                     ls = NULL;
  234.                 }
  235.             }
  236.         }
  237.     }
  238.     return cb;
  239. }
  240.  
  241. /*
  242. **    page_loop()
  243. **
  244. **    send CR/LF or go home and bump letter
  245. */
  246. void
  247. page_loop(void)
  248. {
  249.     if (line_count + 2 >= lines) {
  250.         NEXT_LETTER;
  251.         go_home();
  252.     } else {
  253.         put_crlf();
  254.     }
  255. }
  256.  
  257. /*
  258. **    skip_pad_test(test-list-entry, state, ch, text)
  259. **
  260. **    Print the start test line.  Handle start up commands.
  261. **    Return TRUE if a return is requested.
  262. */
  263. int
  264. skip_pad_test(
  265.     struct test_list *test,
  266.     int *state,
  267.     int *ch,
  268.     const char *text)
  269. {
  270.     char rep_text[16];
  271.  
  272.     while(1) {
  273.         if (text) {
  274.             ptext(text);
  275.         }
  276.         if ((test->flags & MENU_LC_MASK)) {
  277.             sprintf(rep_text, " *%d", augment);
  278.             ptext(rep_text);
  279.         }
  280.         ptext(" [n] > ");
  281.         *ch = wait_here();
  282.         if (*ch == 's') {
  283.             /* Skip is converted to next */
  284.             *ch = 'n';
  285.             return TRUE;
  286.         }
  287.         if (*ch == 'q') {
  288.             /* Quit is converted to help */
  289.             *ch = '?';
  290.             return TRUE;
  291.         }
  292.         if (*ch == '\r' || *ch == '\n' || *ch == 'n' || *ch == 'r') {
  293.             /* this is the only response that allows the test to run */
  294.             *ch = 0;
  295.         }
  296.         if (subtest_menu(pad_test_list, state, ch)) {
  297.             continue;
  298.         }
  299.         return (*ch != 0);
  300.     }
  301. }
  302.  
  303. /*
  304. **    pad_done_message(test_list)
  305. **
  306. **    Print the Done message and request input.
  307. */
  308. void
  309. pad_done_message(
  310.     struct test_list *test,
  311.     int *state,
  312.     int *ch)
  313. {
  314.     int default_action = 0;
  315.     char done_message[128];
  316.     char rep_text[16];
  317.  
  318.     while (1) {
  319.         if ((test->flags & MENU_LC_MASK)) {
  320.             sprintf(rep_text, "*%d", augment);
  321.         } else {
  322.             rep_text[0] = '\0';
  323.         }
  324.         if (test->caps_done) {
  325.             sprintf(done_message, "(%s)%s Done ", test->caps_done,
  326.             rep_text);
  327.             ptext(done_message);
  328.         } else {
  329.             if (rep_text[0]) {
  330.                 ptext(rep_text);
  331.                 ptext(" ");
  332.             }
  333.             ptext("Done ");
  334.         }
  335.         if (debug_level & 2) {
  336.             dump_test_stats(test, state, ch);
  337.         } else {
  338.             *ch = wait_here();
  339.         }
  340.         if (*ch == '\r' || *ch == '\n') {
  341.             *ch = default_action;
  342.             return;
  343.         }
  344.         if (*ch == 's' || *ch == 'n') {
  345.             *ch = 0;
  346.             return;
  347.         }
  348.         if (strchr(pad_repeat_test, *ch)) {
  349.             /* default action is now repeat */
  350.             default_action = 'r';
  351.         }
  352.         if (subtest_menu(pad_test_list, state, ch)) {
  353.             continue;
  354.         }
  355.         return;
  356.     }
  357. }
  358.  
  359. /*
  360. **    sliding_scale(dividend, factor, divisor)
  361. **
  362. **    Return (dividend * factor) / divisor
  363. */
  364. int
  365. sliding_scale(
  366.     int dividend,
  367.     int factor,
  368.     int divisor)
  369. {
  370.     double d = dividend;
  371.  
  372.     if (divisor) {
  373.         d = (d * (double) factor) / (double) divisor;
  374.         return (int) (d + 0.5);
  375.     }
  376.     return 0;
  377. }
  378.  
  379. /*
  380. **    pad_test_startup()
  381. **
  382. **    Do the stuff needed to begin a test.
  383. */
  384. void
  385. pad_test_startup(
  386.     int do_clear)
  387. {
  388.     if (do_clear) {
  389.         put_clear();
  390.     }
  391.     repeats = augment;
  392.     raw_characters_sent = 0;
  393.     test_complete = ttp = char_count = tt_delay_used = 0;
  394.     letter = letters[letter_number = 0];
  395.     if (pad_test_duration <= 0) {
  396.         pad_test_duration = 1;
  397.     }
  398.     tt_delay_max = pad_test_duration * 1000;
  399.     set_alarm_clock(pad_test_duration);
  400.     event_start(TIME_TEST);
  401. }
  402.  
  403. /*
  404. **    still_testing()
  405. **
  406. **    This function is called to see if the test loop should be terminated.
  407. */
  408. int
  409. still_testing(void)
  410. {
  411.     fflush(stdout);
  412.     test_complete++;
  413.     return EXIT_CONDITION;
  414. }
  415.  
  416. /*
  417. **    pad_test_shutdown()
  418. **
  419. **    Do the stuff needed to end a test.
  420. */
  421. void
  422. pad_test_shutdown(
  423.     struct test_list *t,
  424.     int crlf)
  425. {
  426.     int i;
  427.     int counts;            /* total counts */
  428.     int ss;                /* Save string index */
  429.     int cpo;            /* characters per operation */
  430.     int delta;            /* difference in characters */
  431.     int bogus;            /* Time is inaccurate */
  432.     struct test_results *r;        /* Results of current test */
  433.     int ss_index[TT_MAX];        /* String index */
  434.  
  435.     if (tty_can_sync == SYNC_TESTED) {
  436.         bogus = tty_sync_error();
  437.     } else {
  438.         bogus = 1;
  439.     }
  440.     usec_run_time = event_time(TIME_TEST);
  441.     tx_source = t;
  442.     tx_characters = raw_characters_sent;
  443.     tx_cps = sliding_scale(tx_characters, 1000000, usec_run_time);
  444.  
  445.     /* save the data base */
  446.     for (txp = ss = counts = 0; txp < ttp; txp++) {
  447.         tx_cap[txp]   = tt_cap[txp];
  448.         tx_count[txp] = tt_count[txp];
  449.         tx_delay[txp] = tt_delay[txp];
  450.         tx_affected[txp] = tt_affected[txp];
  451.         tx_index[txp] = get_string_cap_byvalue(tt_cap[txp]);
  452.         if (tx_index[txp] >= 0) {
  453.             if (cap_match(t->caps_done, strnames[tx_index[txp]])) {
  454.                 ss_index[ss++] = txp;
  455.                 counts += tx_count[txp];
  456.             }
  457.         }
  458.     }
  459.  
  460.     if (crlf) {
  461.         put_crlf();
  462.     }
  463.     if (counts == 0 || tty_cps == 0 || bogus) {
  464.         /* nothing to do */
  465.         return;
  466.     }
  467.     /* calculate the suggested pad times */
  468.     delta = usec_run_time - sliding_scale(tx_characters, 1000000, tty_cps);
  469.     if (delta < 0) {
  470.         /* probably should bump tx_characters */
  471.         delta = 0;
  472.     }
  473.     cpo = delta / counts;
  474.     for (i = 0; i < ss; i++) {
  475.         if (!(r = get_next_block())) {
  476.             return;
  477.         }
  478.         r->next = pads[tx_index[ss_index[i]]];
  479.         pads[tx_index[ss_index[i]]] = r;
  480.         r->test = t;
  481.         r->reps = tx_affected[ss_index[i]];
  482.         r->delay = cpo;
  483.     }
  484. }
  485.  
  486. /*
  487. **    show_cap_results(index)
  488. **
  489. **    Display the previous results
  490. */
  491. static void
  492. show_cap_results(
  493.     int x)
  494. {
  495.     struct test_results *r;        /* a result */
  496.     int delay;
  497.  
  498.     if ((r = pads[x])) {
  499.         sprintf(temp, "(%s)", strnames[x]);
  500.         ptext(temp);
  501.         while (r) {
  502.             sprintf(temp, "$<%d>", r->delay / 1000);
  503.             put_columns(temp, strlen(temp), 10);
  504.             r = r->next;
  505.         }
  506.         r = pads[x];
  507.         while (r) {
  508.             if (r->reps > 1) {
  509.                 delay = r->delay / (r->reps * 100);
  510.                 sprintf(temp, "$<%d.%d*>", delay / 10, delay % 10);
  511.                 put_columns(temp, strlen(temp), 10);
  512.             }
  513.             r = r->next;
  514.         }
  515.         put_crlf();
  516.     }
  517. }
  518.  
  519. /*
  520. **    dump_test_stats(test_list, status, ch)
  521. **
  522. **    Dump the statistics about the last test
  523. */
  524. void
  525. dump_test_stats(
  526.     struct test_list *t,
  527.     int *state,
  528.     int *ch)
  529. {
  530.     int i, j;
  531.     char tbuf[32];
  532.     int x[32];
  533.  
  534.     put_crlf();
  535.     if (tx_source && tx_source->caps_done) {
  536.         cap_index(tx_source->caps_done, x);
  537.         if (x[0] >= 0) {
  538.             sprintf(temp, "Caps summary for (%s)",
  539.                 tx_source->caps_done);
  540.             ptextln(temp);
  541.             for (i = 0; x[i] >= 0; i++) {
  542.                 show_cap_results(x[i]);
  543.             }
  544.             put_crlf();
  545.         }
  546.     }
  547.     sprintf(tbuf, "%011u", usec_run_time);
  548.     sprintf(temp, "Test time: %d.%s, characters per second %d, characters %d",
  549.         usec_run_time / 1000000, &tbuf[5], tx_cps, tx_characters);
  550.     ptextln(temp);
  551.     for (i = 0; i < txp; i++) {
  552.         if ((j = get_string_cap_byvalue(tx_cap[i])) >= 0) {
  553.             sprintf(tbuf, "(%s)", strnames[j]);
  554.         } else {
  555.             strcpy(tbuf, "(?)");
  556.         }
  557.         sprintf(temp, "%8d  %3d  $<%3d>  %8s %s",
  558.             tx_count[i], tx_affected[i], tx_delay[i],
  559.             tbuf, expand(tx_cap[i]));
  560.         putln(temp);
  561.     }
  562.     generic_done_message(t, state, ch);
  563. }
  564.  
  565. /*
  566. **    longer_test_time(test_list, status, ch)
  567. **
  568. **    Extend the number of seconds for each test.
  569. */
  570. void
  571. longer_test_time(
  572.     struct test_list *t GCC_UNUSED,
  573.     int *state GCC_UNUSED,
  574.     int *ch)
  575. {
  576.     pad_test_duration += 1;
  577.     sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
  578.         pad_test_duration + 1);
  579.     sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
  580.         pad_test_duration - 1);
  581.     sprintf(temp, "Tests will run for %d seconds", pad_test_duration);
  582.     ptext(temp);
  583.     *ch = REQUEST_PROMPT;
  584. }
  585.  
  586. /*
  587. **    shorter_test_time(test_list, status, ch)
  588. **
  589. **    Shorten the number of seconds for each test.
  590. */
  591. void
  592. shorter_test_time(
  593.     struct test_list *t GCC_UNUSED,
  594.     int *state GCC_UNUSED,
  595.     int *ch)
  596. {
  597.     if (pad_test_duration > 1) {
  598.         pad_test_duration -= 1;
  599.         sprintf(txt_longer_test_time, "+) Change test time to %d seconds",
  600.             pad_test_duration + 1);
  601.         sprintf(txt_shorter_test_time, "-) Change test time to %d seconds",
  602.             pad_test_duration - 1);
  603.     }
  604.     sprintf(temp, "Tests will run for %d second%s", pad_test_duration,
  605.         pad_test_duration > 1 ? "s" : "");
  606.     ptext(temp);
  607.     *ch = REQUEST_PROMPT;
  608. }
  609.  
  610. /*
  611. **    longer_augment(test_list, status, ch)
  612. **
  613. **    Lengthen the number of lines/characters effected
  614. */
  615. void
  616. longer_augment(
  617.     struct test_list *t,
  618.     int *state GCC_UNUSED,
  619.     int *ch)
  620. {
  621.     augment <<= 1;
  622.     set_augment_txt();
  623.     if (augment_test) {
  624.         t = augment_test;
  625.     }
  626.     sprintf(temp, "The pad tests will effect %d %s.", augment,
  627.         ((t->flags & MENU_LC_MASK) == MENU_lines) ?
  628.         "lines" : "characters");
  629.     ptextln(temp);
  630.     *ch = REQUEST_PROMPT;
  631. }
  632.  
  633. /*
  634. **    shorter_augment(test_list, status, ch)
  635. **
  636. **    Shorten the number of lines/characters effected
  637. */
  638. void
  639. shorter_augment(
  640.     struct test_list *t,
  641.     int *state GCC_UNUSED,
  642.     int *ch)
  643. {
  644.     if (augment > 1) {
  645.         /* don't let the augment go to zero */
  646.         augment >>= 1;
  647.     }
  648.     set_augment_txt();
  649.     if (augment_test) {
  650.         t = augment_test;
  651.     }
  652.     sprintf(temp, "The pad tests will effect %d %s.", augment,
  653.         ((t->flags & MENU_LC_MASK) == MENU_lines) ?
  654.         "lines" : "characters");
  655.     ptextln(temp);
  656.     *ch = REQUEST_PROMPT;
  657. }
  658.